package com.xk._03真题骗._03栈_队列;

import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;

/*
 * @description: https://leetcode.cn/problems/sliding-window-maximum/
 * @author: xu
 * @date: 2022/10/30 7:59
 */
public class _239滑动窗口最大值 {
    public static void main(String[] args) {
        int[] nums = new int[10_0000];
        int index = 0;
        for (int i = 10000; i > 0; i--) {
            for (int i1 = 0; i1 < 10; i1++) {
                nums[index++] = i;
            }
        }
        long begin = System.currentTimeMillis();
        int[] ints = new _239滑动窗口最大值().maxSlidingWindow(nums, 5000);
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
        System.out.println(Arrays.toString(ints));
    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k < 1) return null;
        if (k == 1) return nums;
        int[] maxRes = new int[nums.length - k + 1];
        int maxIdx = 0;
        for (int i = 1; i < k; i++) {
            if (nums[i] > nums[maxIdx]) maxIdx = i;
        }
        for (int li = 0; li < maxRes.length; li++) {
            int ri = li + k - 1;
            if (maxIdx < li) {
                maxIdx = li;
                for (int i = li + 1; i <= ri; i++) {
                    if (nums[i] > nums[maxIdx]) maxIdx = i;
                }
            } else if (nums[ri] >= nums[maxIdx]){
                maxIdx = ri;
            }
            maxRes[li] = nums[maxIdx];
        }
        return maxRes;
    }

    public int[] maxSlidingWindow_byDeque(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k < 1) return null;
        if (k == 1) return nums;
        // peek: 取值（偷偷瞥一眼）
        // poll: 删除（削）
        // offer: 添加（入队）
        Deque<Integer> deque = new LinkedList<>();
        int[] maxResults = new int[nums.length - k + 1];
        for (int ri = 0; ri < nums.length; ri++) {
            // 只要nums[队尾] <= nums[i]，就删除队尾
            while (!deque.isEmpty() && nums[ri] >= nums[deque.peekLast()]){
                deque.pollLast();
            }
            // 将i加到队尾
            deque.offerLast(ri);
            // 检查窗口的索引是否合法
            int li = ri - k + 1;
            if (li < 0) continue;
            // 检查队头的合法性
            if (deque.peekFirst() < li){
                // 队头不合法（失效，不在滑动窗口索引范围内）
                deque.pollFirst();
            }
            // 设置窗口的最大值
            maxResults[li] = nums[deque.peekFirst()];
        }
        return maxResults;
    }
}
